#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations

import os
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any

from autoapi.common.log import log


class BaseFileHandler(ABC):
    """基础文件处理器抽象类，提供文件操作的公共逻辑"""
    
    @staticmethod
    def _get_full_path(filepath: str, filename: str | None = None) -> str:
        """获取完整文件路径"""
        if filename:
            return os.path.join(filepath, filename)
        return filepath

    @staticmethod
    def _ensure_directory_exists(filepath: str) -> None:
        """确保目录存在"""
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)

    @classmethod
    def read_file(
        cls,
        filepath: str,
        filename: str | None = None,
        encoding: str = 'utf-8',
        **kwargs
    ) -> Any:
        """
        读取文件基础方法
        
        :param filepath: 文件路径
        :param filename: 文件名
        :param encoding: 文件编码
        :param kwargs: 其他参数
        :return: 文件内容
        """
        full_path = cls._get_full_path(filepath, filename)
        try:
            with open(full_path, encoding=encoding) as f:
                data = cls._load(f, **kwargs)
        except Exception as e:
            log.error(f'文件 {filename or filepath} 读取错误: {e}')
            raise e
        
        if data is None:
            log.warning(f'数据文件 {filename or filepath} 没有数据!')
            raise ValueError(f'数据文件 {filename or filepath} 没有数据!')
        return data

    @classmethod
    def write_file(
        cls,
        filepath: str,
        filename: str,
        data: Any = None,
        *,
        encoding: str = 'utf-8',
        mode: str = 'a',
        **kwargs
    ) -> None:
        """
        写入文件基础方法
        
        :param filepath: 文件路径
        :param filename: 文件名
        :param data: 要写入的数据
        :param encoding: 文件编码
        :param mode: 写入模式
        :param kwargs: 其他参数
        """
        full_path = cls._get_full_path(filepath, filename)
        cls._ensure_directory_exists(full_path)
        
        try:
            with open(full_path, encoding=encoding, mode=mode) as f:
                cls._dump(data, f, **kwargs)
        except Exception as e:
            log.error(f'写入文件 "{filename}" 错误: {e}')
            raise e
        else:
            log.info(f'写入文件 {filename} 成功')

    @staticmethod
    @abstractmethod
    def _load(file_obj, **kwargs) -> Any:
        """抽象方法：从文件对象加载数据"""
        pass

    @staticmethod
    @abstractmethod
    def _dump(data: Any, file_obj, **kwargs) -> None:
        """抽象方法：将数据写入文件对象"""
        pass
